package com.choosefine.paycenter.settlement.service.impl;

import com.choosefine.paycenter.account.dto.AccountWdDto;
import com.choosefine.paycenter.account.model.Account;
import com.choosefine.paycenter.account.model.AccountBalanceLog;
import com.choosefine.paycenter.account.model.AccountBill;
import com.choosefine.paycenter.account.model.ShiXiaoBaoTrx;
import com.choosefine.paycenter.account.service.AccountBalanceLogService;
import com.choosefine.paycenter.account.service.AccountBillService;
import com.choosefine.paycenter.account.service.AccountService;
import com.choosefine.paycenter.account.service.ShiXiaoBaoTrxService;
import com.choosefine.paycenter.common.component.RedisLock;
import com.choosefine.paycenter.common.constants.ExceptionCodeConstants;
import com.choosefine.paycenter.common.constants.ExceptionMessageConstants;
import com.choosefine.paycenter.common.enums.BizzSys;
import com.choosefine.paycenter.common.enums.FundFlowDirection;
import com.choosefine.paycenter.common.exception.BusinessException;
import com.choosefine.paycenter.common.utils.MessageSourceUtils;
import com.choosefine.paycenter.pay.service.ChannelService;
import com.choosefine.paycenter.settlement.dao.WithdrawMapper;
import com.choosefine.paycenter.settlement.model.Withdraw;
import com.choosefine.paycenter.settlement.service.WithdrawService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

/**
 * @author 潘钱钦（qianqinpan@outlook.com）
 * @create 2017-05-05 11:46
 **/
@Slf4j
@Service
public class WithdrawServiceImpl implements WithdrawService {
    @Autowired
    private WithdrawMapper withdrawMapper;

    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountBalanceLogService accountBalanceLogService;

    @Autowired
    private AccountBillService accountBillService;

    @Autowired
    private ChannelService channelService;

    @Autowired
    private ShiXiaoBaoTrxService  shiXiaoBaoTrxService;

    @Autowired
    MessageSourceUtils localeMessageSourceUtils;

    /**
     * 账户余额锁标志
     */
    public final static String UNIQUE_ACCOUNT_BALANCE = "UNIQUE_ACCOUNT_BALANCE_";

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public long addWithdraw(Withdraw withdraw) {
        return withdrawMapper.insertSelective(withdraw);
    }

    @Override
    public long updateWithdraw(Withdraw withdraw) {
        return withdrawMapper.updateByPrimaryKeySelective(withdraw);
    }

    @Override
    public Withdraw selectByWSn(String wSn) {
        return withdrawMapper.selectByWSn(wSn);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateAfterWithdrawSuccess(Withdraw withdraw) {
        RedisLock mainAccountLock = null;
        Account account= accountService.findById(withdraw.getAccountId());
        String userCode= account.getUserCode();
        try {
            mainAccountLock = new RedisLock(redisTemplate, UNIQUE_ACCOUNT_BALANCE + userCode);
            mainAccountLock.lock();
            AccountWdDto accountDTO = null;
            AccountBalanceLog accountBalanceLog = null;

            AccountBill accountBill =null;
            //成功了更新账户的余额
            BigDecimal availableBalance = account.getBalance().subtract(withdraw.getAmount());
            accountDTO = new AccountWdDto();
            accountDTO.setAccountId(withdraw.getAccountId());
            accountDTO.setAvailableBalance(availableBalance);
            accountDTO.setBalance(availableBalance);
            accountDTO.setFreezeBalance(new BigDecimal(0.00));
            accountService.updateAccountBalanceBeforWithDraw(accountDTO);
            //记录账户余额变更记录
            accountBalanceLog = new AccountBalanceLog();
            accountBalanceLog.setAccountId(withdraw.getAccountId());
            accountBalanceLog.setAccountUserCode(userCode);
            accountBalanceLog.setAccountRealName(account.getRealName());
            accountBalanceLog.setNewAvailableBalance(availableBalance);
            accountBalanceLog.setNewBalance(availableBalance);
            accountBalanceLog.setNewFreezeBalance(new BigDecimal(0.00));
            accountBalanceLog.setOldAvailableBalance(account.getAvailableBalance());
            accountBalanceLog.setOldBalance(account.getBalance());
            accountBalanceLog.setOldFreezeBalance(withdraw.getAmount());
            accountBalanceLog.setChangeDesc("提现流水号["+withdraw.getWSn()+"],账户冻结余额-"+account.getFreezeBalance()+",账户账户总余额-" + withdraw.getAmount());
            accountBalanceLogService.recordAccountBalanceLog(accountBalanceLog);
            //记录施小包流水
            ShiXiaoBaoTrx shiXiaoBaoTrx = new ShiXiaoBaoTrx();
            shiXiaoBaoTrx.setTradeSn(withdraw.getWSn());
            shiXiaoBaoTrx.setAccountId(withdraw.getAccountId());
            shiXiaoBaoTrx.setUserCode(userCode);
            shiXiaoBaoTrx.setUserName(withdraw.getAccountRealName());
            shiXiaoBaoTrx.setOperName(withdraw.getOperName());
            shiXiaoBaoTrx.setType(FundFlowDirection.WITHDRAW);
            shiXiaoBaoTrx.setBankcardName(withdraw.getBankcardName());
            shiXiaoBaoTrx.setBankcardNo(withdraw.getBankcardNo());
            shiXiaoBaoTrx.setAmount(withdraw.getAmount());
            shiXiaoBaoTrxService.recordShixiaobaoTrx(shiXiaoBaoTrx);
            //更新账单状态为完成
            accountBillService.updateAccountBillSuccess(BizzSys.SELF,withdraw.getWSn());
            return 1;
        } catch (Exception e) {
            log.error("更新提现记录失败,提现流水号为：" + withdraw.getWSn() + "提现银行请求流水号为：" + withdraw.getBankRequestSn());
            return 0;
        } finally {
            if (null != mainAccountLock) {
                mainAccountLock.unlock();
            }
        }
    }

    @Override
    public List<Withdraw> selectByStatus() {
        return withdrawMapper.selectByStatus();
    }

    @Override
    public void checkHasWaittingWithdraw(Long accountId) {
       Withdraw withdraw= withdrawMapper.selectWaitingWsByAccId(accountId);
       if (null!=withdraw){
           throw new BusinessException(ExceptionCodeConstants.WITHDRAW_IS_EXIT,localeMessageSourceUtils.getMessage(ExceptionMessageConstants.WITHDRAW_IS_ALREADY_EXIT));
       }
    }
}
